/*
 * ============================================================================
 *
 *       Filename:  QQWryLookup.cpp
 *
 *    Description:  
 *
 *         Author:  liangqing
 *
 * ============================================================================
 */
#include "QQWryLookup.h"

namespace {
    inline int bytes2int(char *bytes, int size) {
        unsigned int ret;
        ret = ((unsigned char)bytes[0]);
        ret |= ((unsigned char)bytes[1] << 8);
        ret |= ((unsigned char)bytes[2] << 16);
        if(size > 3)
            ret |= ((unsigned char)bytes[3] << 24);
        return ret;
    }

}

QQWryLookup::QQWryLookup(const char *filename) : _qqwry(filename, std::ios::binary) {
    //_qqwry = fopen(filename, "rb");
    
    if(!_qqwry) {
        std::cerr << "fail to open " << filename << std::endl;
        return;
    }
    //_buf = new char[1024];
    _sbuf = _qqwry.rdbuf();
    //_sbuf->pubsetbuf(_buf, 1024);
    //_buf = new char[4096];
    //cout << setvbuf(_qqwry, NULL, _IOFBF, 1024) << endl;
    //_flush_rbuf();

    char offset[4];
    _first_index = _pos(offset, sizeof(offset));
    _last_index = _pos(offset, sizeof(offset));
    _total = (_last_index - _first_index) / Index::size + 1;
    _seek(_first_index);
}

int QQWryLookup::_pos(char *offset, int size) {
    _read(offset, size);
    return bytes2int(offset, size);
}

bool QQWryLookup::get(IPRecord *record) {
    int index_pos, pos;
    bool ret;
    char offset[3];
    index_pos = _tell();
    
    if(!_read((char *)record->begin_ip, sizeof(record->begin_ip))) return false;
    pos = _pos(offset, sizeof(offset));
    if(!_seek(pos)) return false;
    
    ret = read_record(record);
    if(!_seek(index_pos+7)) return false;
    return ret;
}

int QQWryLookup::read_all() {
    IPRecord _record;
    IPRecord *record = &_record;
    int i=0, pos;
    Index *indexes = new Index[_total];

    //ofstream out("1.txt"); 
    _read((char *)indexes, _total * Index::size);
    
    for(; i < _total; i++) {
        memcpy(record->begin_ip, indexes[i].ip, sizeof(record->begin_ip));
        pos = bytes2int(indexes[i].offset, sizeof(indexes[i].offset));
        if(!_seek(pos)) return i;
        read_record(record);
        //out << *record << endl;
    }

    delete []indexes;
    return i;
}

bool QQWryLookup::read_record(IPRecord *record) {
    char offset[3];
    int pos;
    int remain=0;
    char mode;
    int find = 0;
    
    if(!_read((char *)record->end_ip, sizeof(record->end_ip))) return false;
    
    while(true) {
        mode=_peek();
        if(mode!=0x1 && mode!=0x2) {
            if(find == 0) {
                if(!_getn(record->region, sizeof(record->region), '\0')) return false;
            }
            else {
                if(!_getn(record->section, sizeof(record->section), '\0')) return false;
            }
            find++;
            if(find >= 2) {
                return true;
            }
            else if(remain > 0){
                if(!_seek(remain)) return false;
                remain = 0;
                continue;
            }
            continue;
        }

        if(mode == 0x1) {
            _getc();
            pos = _pos(offset, sizeof(offset));
            if(!_seek(pos)) return false;
            continue;
        }

        if(mode == 0x2) {
            _getc();
            pos = _pos(offset, sizeof(offset));
            remain = _tell();
            if(!_seek(pos)) return false;
        }
    }
}

